; LocalDisplay module, written by Vincent Lefvre
; Freeware.

; $Id: localdisp 2.0 2003/05/25 09:55:05 vlefevre Exp $

		GET	h:RegNames
		GET	h:SWINames
		GET	h:RCSsupport

; If you don't have the Tracker library, comment out the
; following GET line and uncomment the two macros.

		GET	h:DebugHdr

;		MACRO
;$label		DBSET	$flags, $cc
;$label
;		MEND
;
;		MACRO
;$label		DBF	$argstr, $cc
;$label
;		MEND

		GBLL	Debug
Debug		SETL	{FALSE}

		GETVERS	"$Revision: 2.0 $"
		GETDATE	"$Date: 2003/05/25 09:55:05 $"

		GBLS	NAME
NAME		SETS	"Local Display"
		GBLS	AUTHOR
AUTHOR		SETS	"Vincent Lefvre"
		GBLS	VERSION
VERSION		SETS	VERS:CC:" (":CC:DATE:CC:")"

		^	0
		#	4	;Task handle.
FREG		#	4	;Filter routine or 0.
DISPADDR	#	4	;Address of display options.
FILER		#	4	;Filer's task handle.
DISPVAL		#	1	;Saved display options.
VALID		#	1	;Zero if the above is valid.
STATUS		#	1	;Status (0: off, 1: on).
KEY		#	1	;Special key.
BUFFER		#	256	;Buffer.
BUFFER2		#	256	;Buffer for Wimp_SendMessage.
		[	Debug
STACK		#	80	;Stack.
		]
SIZE		#	0	;--> size of workspace.

Service_FD	EQU	&4F	;Service: Filer Dying.
Service_FMI	EQU	&87	;Service: Filter Manager Installed.
Service_FMD	EQU	&88	;Service: Filter Manager Dying.


		AREA	LocalDisplay, CODE, PIC, READONLY
		ENTRY

BaseAddr	DCD	RM_Start  -BaseAddr
		DCD	RM_Init   -BaseAddr
		DCD	RM_Die    -BaseAddr
		DCD	RM_Service-BaseAddr
		DCD	RM_Title  -BaseAddr
		DCD	RM_Help   -BaseAddr
		DCD	RM_HCtable-BaseAddr
		DCD	0,0,0,0,0
		DCD	RM_Flags  -BaseAddr

RM_Flags	DCD	1		;32-bit compatible.

task		DCB	"TASK"
taskname	DCB	NAME,0
		ALIGN
filer		DCB	"Filer",0

		ALIGN

; *****************
; Finalisation code
; *****************

RM_Die		DBF	"RM_Die\n"
		LDR	R2, [R12]	;Pointer to workspace.
		MOV	R6, LR
		LDR	R0, [R2]	;Task handle or 0.
		LDR	R1, task	;"TASK".
		TEQ	R0, #0
		SWINE	XWimp_CloseDown
		LDR	R1, [R2, #FREG]	;Filter routine or 0.
		TEQ	R1, #0		;Filter registered?
		BLNE	params		;Yes, deregister...
		SWINE	XFilter_DeRegisterPostFilter
		B	reset_taskh	;Reset task handle.

; *******************
; Initialisation code
; *******************

RM_Init		DBSET	DebugOn :OR: UseTracker
		DBF	"RM_Init\n"
		LDR	R2, [R12]	;Pointer to workspace or 0.
		MOV	R6, LR
		TEQ	R2, #0
		BNE	reset_taskh
		MOV	R0, #6		;Executed unless re-init.
		MOV	R3, #SIZE
		SWI	XOS_Module	;Claim.
		MOVVS	PC, R6		;Return with V=1 if not enough memory.
		STR	R2, [R12]	;Pointer to workspace.
reset_taskh	SUBS	R0, R0, R0	;R0 = 0. Make sure that V is cleared.
		STR	R0, [R2]	;Reset task handle.
		STR	R0, [R2, #FREG]	;Reset filter routine address.
		STRB	R0, [R2, #STATUS] ;Reset status.
		STRB	R0, [R2, #KEY]	;Reset special key.
		MOV	PC, R6

; **************
; Filter routine
; **************

filter		TEQ	R0, #9		;Menu selection?
		MOVNE	PC, LR		;No, return (shouldn't happen).
		STMFD	SP!, {R0-R2,LR}	;Menu selection (Filer).
		LDR	R0, [R1]
		TEQ	R0, #0		;Display submenu?
		LDMNEFD	SP!, {R0-R2,PC}	;No, return.
		LDR	R0, [R1, #4]
		CMP	R0, #6
		LDMHIFD	SP!, {R0-R2,PC}	;Return if not a display option.
		DBF	"Display submenu selection (Filer)\n"
		LDRB	R1, [R12, #KEY]	;Special key.
		MOV	R0, #121
		ORR	R1, R1, #&80
		SWI	XOS_Byte	;Keyboard scan.
		LDMVSFD	SP!, {R0-R2,PC}	;Return if error.
		LDRB	R0, [R12, #STATUS]
		TEQ	R1, #&FF	;If key pressed:
		EOREQ	R0, R0, #1	;toggle the status.
		TEQ	R0, #0		;--> NE if local setting.
		LDRNE	R1, [R12, #DISPADDR]
		TEQNE	R1, #0		 ;Return if global setting
		LDMEQFD	SP!, {R0-R2,PC}	;or if Filer has died.
		LDRB	R0, [R1]
		MOV	R2, #0
		STRB	R0, [R12, #DISPVAL]
		STRB	R2, [R12, #VALID]
		MOV	R0, #13		;Reason: pollword non-zero.
		ADD	R1, R12, #BUFFER2
		LDR	R2, [R12]	;Task LocalDiplay.
		SWI	XWimp_SendMessage
		LDMFD	SP!, {R0-R2,PC}

; **************
; Routine params
; **************

params		ADR	R0, RM_Title	;Filter name: LocalDisplay.
		ADR	R1, filter	;Filter routine.
		LDR	R3, [R2, #FILER] ;Applies to Filer.
		MVN	R4, #1<<9	;Event mask: menu selection.
		MOV	PC, LR		;Return (flags not modified).

; ************
; Service code
; ************

		DCD	ServiceTable-BaseAddr
RM_Service	MOV	R0, R0		;Magic instruction for Ursula kernel.
		TEQ	R1, #Service_FD
		TEQNE	R1, #Service_FMI
		TEQNE	R1, #Service_FMD
		MOVNE	PC, LR		;Return if not FD, FMI or FMD.
RM_FastServ     TEQ	R1, #Service_FD
		BEQ	Filer_Dying
		TEQ	R1, #Service_FMI
		BEQ	FM_Installed
FM_Dying	STMFD	SP!, {R2,LR}	;Filter Manager Dying.
		LDR	R2, [R12]	;Pointer to workspace.
		MOV	R14, #0
		STR	R14, [R2, #FREG]
		LDMFD	SP!, {R2,PC}
FM_Installed	STMFD	SP!, {R0-R4,LR}	;Filter Manager Installed.
		LDR	R2, [R12]	;Pointer to workspace.
		BL	params
		SWI	XFilter_RegisterPostFilter
		MOVVS	R1, #0		;R1 = 0 if error.
		STR	R1, [R2, #FREG]
		LDMFD	SP!, {R0-R4,PC}
Filer_Dying	STMFD	SP!, {R0-R4,LR}	;Filer Dying.
		LDR	R2, [R12]	;Pointer to workspace.
		BL	params
		SWI	XFilter_DeRegisterPostFilter
		MOV	R1, #0
		STR	R1, [R2, #FREG]
		STR	R1, [R2, #DISPADDR]
		LDMFD	SP!, {R0-R4,PC}

; **********
; Start code
; **********

RM_Start	LDR	R6, [R12]	;R6: pointer to workspace.
		[	Debug
		ADD	SP, R6, #SIZE
		DBF	"RM_Start\n"
		]

		LDR	R0, [R6]	;Task handle or 0.
		TEQ	R0, #0
		BEQ	start2
		LDR	R1, task	;"TASK".
		SWI	Wimp_CloseDown
		MOV	R0, #0
		STR	R0, [R6]	;Reset task handle.

start2		ADR	R2, taskname
		MOV	R0, #300
		ADD	R0, R0, #10	;Last Wimp version known: 3.10.
		LDR	R1, task	;"TASK".
		MOV	R3, #0		;No important messages.
		SWI	XWimp_Initialise
		ADR	R3, RM_Title	;R3 = module name.
		SWIVS	OS_ExitAndDie
		STR	R1, [R6]	;Store task handle.
		DBF	"Started (task handle: &%1h)\n"

		MOV	R0, #18
		ADR	R1, filer
		SWI	XOS_Module	;Lookup module name.
		SWIVS	OS_ExitAndDie
		DBF	"Filer's private word: &%4w\n"
		ADD	R4, R4, #&4A	;Offset to display options.
		STR	R4, [R6, #DISPADDR]

		MOV	R0, #0
filer_outer	TEQ	R0, #0
		SWIMI	OS_ExitAndDie	;Exit if task Filer not found.
		ADD	R1, R6, #BUFFER
		MOV	R2, #256
		SWI	XTaskManager_EnumerateTasks
		SWIVS	OS_ExitAndDie
		ADD	R2, R6, #BUFFER
filer_inner	TEQ	R1, R2
		BEQ	filer_outer
		LDR	R4, [R2, #4]	;Task name.
		LDRB	R5, [R4], #1
		TEQ	R5, #'F'
		LDREQB	R5, [R4], #1
		TEQEQ	R5, #'i'
		LDREQB	R5, [R4], #1
		TEQEQ	R5, #'l'
		LDREQB	R5, [R4], #1
		TEQEQ	R5, #'e'
		LDREQB	R5, [R4], #1
		TEQEQ	R5, #'r'
		LDREQB	R5, [R4]
		TEQEQ	R5, #0
		ADDNE	R2, R2, #16
		BNE	filer_inner
		LDR	R0, [R2]	;Filer's task handle.
		STR	R0, [R6, #FILER]
		DBF	"Filer's task handle: &%0h\n"

		LDR	R1, [R6, #FREG]	;Filter routine or 0.
		TEQ	R1, #0
		BNE	loop		;Branch if already registered.
		MOV	R2, R6		;Pointer to workspace.
		BL	params
		SWI	XFilter_RegisterPostFilter
		MOVVS	R1, #0		;R1 = 0 if error (FM not present?).
		STR	R1, [R6, #FREG]

loop		MOV	R0, #&1800	;Mask: &1831.
		ORR	R0, R0, #&31
		STRB	R0, [R6, #VALID]
		ADD	R1, R6, #BUFFER
		SWI	XWimp_Poll
		ADR	R3, RM_Title
		SWIVS	OS_ExitAndDie
		TEQ	R0, #17		;UserMessage?
		TEQNE	R0, #18		;UserMessage_Recorded?
		BNE	pollword	;No, branch.
		LDR	R0, [R1, #16]	;Message code.
		TEQ	R0, #0		;Quit?
		BNE	loop		;No, loop.
		DBF	"Quit\n"
		SWI	OS_ExitAndDie	;Yes, die.

pollword	TEQ	R0, #13		;Pollword non-zero?
		LDREQB	R0, [R6, #VALID]
		TEQ	R0, #0		;Valid display options?
		DBF	"Restore display options\n", EQ
		LDREQB	R0, [R6, #DISPVAL] ;Exec the following if yes.
		LDREQ	R1, [R6, #DISPADDR]
		STREQB	R0, [R1]
		B	loop

; *****************
; LocalDisplay code
; *****************

LD		DBF	"*LocalDisplay\n"
		LDR	R12, [R12, #0]	;R12: pointer to workspace.
		MOV	R5, LR
		TEQ	R1, #0
		BNE	set_status
		LDRB	R0, [R12, #STATUS]
		TEQ	R0, #0
		ADREQ	R0, status_off
		ADRNE	R0, status_on
		SWI	XOS_Write0
		SWIVC	XOS_NewLine
		MOV	PC, R5

set_status	LDRB	R1, [R0]
		BIC	R1, R1, #&20
		TEQ	R1, #'O'
		BNE	LD_error
		LDRB	R1, [R0, #1]
		LDRB	R2, [R0, #2]
		BIC	R1, R1, #&20
		TEQ	R1, #'N'
		MOVEQ	R3, #1
		BEQ	LD_on
		TEQ	R1, #'F'
		BNE	LD_error
		BIC	R2, R2, #&20
		TEQ	R2, #'F'
		BNE	LD_error
		LDRB	R2, [R0, #3]
		MOV	R3, #0
LD_on		CMP	R2, #' '	;Note: V = 0 as R2 is a 8-bit number.
		STRLSB	R3, [R12, #STATUS]
		MOVLS	PC, R5
LD_error	MOV	R1, #&40000000
		ADDS	R1, R1, R1	;Set V flag.
		ADR	R0, error
		MOV	PC, R5

error		DCD	0
		DCB	"Unknown operand",0
status_off	DCB	"Off",0
status_on	DCB	"On",0
		ALIGN

; *********************
; LocalDisplaySKey code
; *********************

LDSK		DBF	"*LocalDisplaySKey\n"
		LDR	R12, [R12, #0]	;R12: pointer to workspace.
		MOV	R5, LR
		TEQ	R1, #0
		BNE	set_skey
		LDRB	R0, [R12, #KEY]	;Display the special key...
		ADD	R1, R12, #BUFFER2
		MOV	R2, #16
		SWI	XOS_ConvertCardinal1
		SWIVC	XOS_Write0
		SWIVC	XOS_NewLine
		MOV	PC, R5

set_skey	MOV	R1, R0		;Set the special key...
		MOV	R2, #&7F	;Must be in the range [0,&7F].
		MOV	R0, #10+(5<<29)
		SWI	XOS_ReadUnsigned
		STRVCB	R2, [R12, #KEY]
		MOV	PC, R5

; *************************
; Desktop_LocalDisplay code
; *************************

Desktop		MOV	R6, LR
		MOV	R2, R0
		ADR	R1, RM_Title
		MOV	R0, #2
		SWI	XOS_Module	;Enter LocalDisplay.
		MOV	PC, R6

; *********
; Some data
; *********

ServiceTable	DCD	0, RM_FastServ-BaseAddr
		DCD	Service_FD, Service_FMI, Service_FMD, 0

RM_HCtable	DCB	"Desktop_"
RM_Title	DCB	"LocalDisplay",0
		ALIGN
		DCD	Desktop-BaseAddr,0,0,Help_Desktop-BaseAddr
		DCB	"LocalDisplay",0
		ALIGN
		DCD	LD-BaseAddr
		DCB	0,0,1,0
		DCD	Synt_LD-BaseAddr,Help_LD-BaseAddr
		DCB	"LocalDisplaySKey",0
		ALIGN
		DCD	LDSK-BaseAddr
		DCB	0,1,1,0
		DCD	Synt_LDSK-BaseAddr,Help_LDSK-BaseAddr
		DCB	0

RM_Help		DCB	NAME,9,VERSION," by ",AUTHOR,0

Help_Desktop	DCB	"Do not use *",27,0,", use *Desktop instead.",0
Help_LD		DCB	"*",27,0," ",27,19,27,8,"behaviour of ",NAME,".",13
		DCB	"If used with no ",27,36,"s, it",27,32,27,2,27,5
		DCB	" status.",13
Synt_LD		DCB	27,30,"On|Off]",0
Help_LDSK	DCB	"*",27,0," sets or",27,32,27,2,NAME," special key.",13
Synt_LDSK	DCB	27,30,"<key>]",0

		END
